package com.uduemc.biso.node.web.api.controller;

import java.io.File;
import java.io.IOException;

import org.apache.commons.io.FileUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.DigestUtils;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RequestPart;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.uduemc.biso.core.extities.center.Host;
import com.uduemc.biso.core.extities.center.Site;
import com.uduemc.biso.core.extities.node.custom.LoginNode;
import com.uduemc.biso.core.property.uploadpro.UploadCommon;
import com.uduemc.biso.core.utils.FileZip;
import com.uduemc.biso.core.utils.JsonResult;
import com.uduemc.biso.node.core.entities.HRepertory;
import com.uduemc.biso.node.core.entities.SConfig;
import com.uduemc.biso.node.core.node.config.OperateLoggerStaticModel;
import com.uduemc.biso.node.core.node.config.OperateLoggerStaticModelAction;
import com.uduemc.biso.node.core.operate.entities.OperateLog;
import com.uduemc.biso.node.core.property.GlobalProperties;
import com.uduemc.biso.node.core.utils.FilterResponse;
import com.uduemc.biso.node.core.utils.SitePathUtil;
import com.uduemc.biso.node.web.api.component.RequestHolder;
import com.uduemc.biso.node.web.api.component.TemplateAsync;
import com.uduemc.biso.node.web.api.exception.HostSetuptException;
import com.uduemc.biso.node.web.api.service.SConfigService;
import com.uduemc.biso.node.web.api.service.UploadService;
import com.uduemc.biso.node.web.api.service.WebSiteService;
import com.uduemc.biso.node.web.api.service.hostsetup.HSUploadSizeService;
import com.uduemc.biso.node.web.component.operate.OperateLoggerController;
import com.uduemc.biso.node.web.service.OperateLoggerService;

import lombok.extern.slf4j.Slf4j;

@RestController
@RequestMapping("/api/upload")
@Slf4j
public class UploadController {

	@Autowired
	private TemplateAsync templateAsync;

	@Autowired
	private GlobalProperties globalProperties;

	@Autowired
	private UploadService uploadServiceImpl;

	@Autowired
	private RequestHolder requestHolder;

	@Autowired
	private WebSiteService webSiteServiceImpl;

	@Autowired
	private SConfigService sConfigServiceImpl;

	@Autowired
	private OperateLoggerService operateLoggerServiceImpl;

	@Autowired
	private HSUploadSizeService hSUploadSizeServiceImpl;

	/**
	 * 获取上传文件允许的文件后缀
	 * 
	 * @return
	 */
	@PostMapping("/allow-ext")
	public JsonResult allowExt() {
		UploadCommon infos = globalProperties.getUpload().getInfos();

		long imageUploadSize = hSUploadSizeServiceImpl.imageUploadSize();
		long fileUploadSize = hSUploadSizeServiceImpl.fileUploadSize();
		long flashUploadSize = hSUploadSizeServiceImpl.flashUploadSize();
		long audioUploadSize = hSUploadSizeServiceImpl.audioUploadSize();
		long videoUploadSize = hSUploadSizeServiceImpl.videoUploadSize();
		long sslUploadSize = hSUploadSizeServiceImpl.sslUploadSize();

		infos.getImage().resetSize(imageUploadSize);
		infos.getFile().resetSize(fileUploadSize);
		infos.getFlash().resetSize(flashUploadSize);
		infos.getAudio().resetSize(audioUploadSize);
		infos.getVideo().resetSize(videoUploadSize);
		infos.getSsl().resetSize(sslUploadSize);

		return JsonResult.ok(infos);
	}

	/**
	 * 上传动作
	 * 
	 * @return
	 * @throws IOException
	 * @throws HostSetuptException
	 */
	@PostMapping("/handle")
	public JsonResult handle(@RequestPart("file") MultipartFile file, @RequestParam(value = "labelId", defaultValue = "0") long labelId)
			throws IOException, HostSetuptException {
		log.info("labelId: " + labelId);
		if (file.isEmpty()) {
			return JsonResult.illegal();
		}
		// 如果现有空间与上传的文件之和大于可以上传的空间大小，则不允许上传！
		JsonResult validSpace = uploadServiceImpl.validSpace(file);
		if (validSpace != null) {
			return validSpace;
		}

		// 验证上传的文件是否符合要求
		JsonResult validFile = uploadServiceImpl.validFile(file);
		if (validFile != null) {
			return validFile;
		}

		// 验证文件的标签是否符合要求
		if (!uploadServiceImpl.validLabelId(labelId)) {
			return JsonResult.illegal();
		}

		HRepertory hRepertory = uploadServiceImpl.nodeUploadHandler(file, labelId);
		if (hRepertory == null) {
			return JsonResult.assistance();
		}
		return JsonResult.ok(FilterResponse.filterRepertoryInfo(hRepertory));
	}

	/**
	 * 上传 favicon.ico 图标
	 * 
	 * @return
	 * @throws IOException
	 * @throws HostSetuptException
	 */
	@PostMapping("/favicon")
	public JsonResult favicon(@RequestPart("file") MultipartFile file) throws IOException, HostSetuptException {
		if (file.isEmpty()) {
			return JsonResult.illegal();
		}
		// 通过 basePath 以及 code 获取 用户的目录
		String filefullpath = SitePathUtil.getUserFaviconIcoPathByCode(globalProperties.getSite().getBasePath(), requestHolder.getHost().getRandomCode());

		File faviconFile = new File(filefullpath.toString());
		// 删除原来的图片
		if (faviconFile.isFile()) {
			faviconFile.delete();
		}
		file.transferTo(faviconFile);
		webSiteServiceImpl.cacheCurrentSiteClear();
		return JsonResult.ok();
	}

	@PostMapping("/favicon-delete")
	public JsonResult favicondelete() throws IOException, HostSetuptException {
		// 通过 basePath 以及 code 获取 用户的目录
		String filefullpath = SitePathUtil.getUserFaviconIcoPathByCode(globalProperties.getSite().getBasePath(), requestHolder.getHost().getRandomCode());

		File faviconFile = new File(filefullpath.toString());
		// 删除原来的图片
		if (faviconFile.isFile()) {
			faviconFile.delete();
		}
		webSiteServiceImpl.cacheCurrentSiteClear();
		return JsonResult.ok(1);
	}

	/**
	 * 上传 template 动作
	 * 
	 * @return
	 * @throws Exception
	 */
	@PostMapping("/handle-template")
	public JsonResult handletemplate(@RequestPart("file") MultipartFile file) throws Exception {
		if (file.isEmpty()) {
			return JsonResult.illegal();
		}
		long sz200M = 1024 * 1024 * 200;
		if (file.getSize() > sz200M) {
			return JsonResult.messageError("文件大小不能超过200M！");
		}
		Host host = requestHolder.getHost();
		Site currentSite = requestHolder.getCurrentSite();

		// 验证配置是否存在
		SConfig sConfig = sConfigServiceImpl.getInfoBySiteId(requestHolder.getHost().getId(), requestHolder.getCurrentSite().getId());
		if (sConfig == null) {
			return JsonResult.illegal();
		}

		Short status = sConfig.getStatus();
		if (status != null && status.shortValue() == (short) 2) {
			return JsonResult.messageWarning("正在初始化中，请稍后！");
		}

		String userTemplatePath = SitePathUtil.getUserTemplateInitPathByCode(globalProperties.getSite().getBasePath(), host.getRandomCode(),
				currentSite.getId());

		String userTemplateFile = userTemplatePath + "/template.zip";

		File userfile = new File(userTemplatePath);
		if (userfile.isDirectory()) {
			FileUtils.deleteDirectory(userfile);
		}
		// 创建目录
		FileUtils.forceMkdir(userfile);

		file.transferTo(new File(userTemplateFile));
		if (!new File(userTemplateFile).isFile()) {
			return JsonResult.messageError("文件转移出现故障！");
		}

		String userTemplateUnzipPath = userTemplatePath + "/template";
		// 解压
		FileZip.decompress(userTemplateUnzipPath, userTemplateUnzipPath);

		if (!new File(userTemplateUnzipPath).isDirectory()) {
			return JsonResult.messageError("文件解压出现故障！");
		}

		// 验证解压的验证文件是否正常
		// 生成验证文件
		File verificationFile = new File(userTemplateUnzipPath + "/verification");
		if (!verificationFile.isFile()) {
			// 删除目录
			FileUtils.deleteDirectory(new File(new File(userTemplateUnzipPath).getParentFile().toString()));
			return JsonResult.messageError("验证压缩文件失败！");
		}
		long sizeOfDirectory = FileUtils.sizeOfDirectory(new File(userTemplateUnzipPath + "/data"));
		String verification = DigestUtils.md5DigestAsHex(String.valueOf(sizeOfDirectory).getBytes());
		String readFileToString = FileUtils.readFileToString(verificationFile, "UTF-8");
		if (!verification.equals(readFileToString)) {
			log.info("验证的密码：" + verification);
			log.info("验证文件内的密码：" + readFileToString);
			// 删除目录
			FileUtils.deleteDirectory(new File(new File(userTemplateUnzipPath).getParentFile().toString()));
			return JsonResult.messageError("验证压缩文件失败！");
		}

		// 首先锁定host下的site站点
		sConfig.setStatus((short) 2);
		SConfig updateSConfig = sConfigServiceImpl.updateAllSiteConfig(sConfig);
		if (updateSConfig == null) {
			return JsonResult.assistance();
		}

		// 写入正在执行的日志
		OperateLog insert = handletemplateLog(file.getOriginalFilename(), "MultipartFile file");
		if (insert == null) {
			return JsonResult.assistance();
		}
		// 变更site_config的状态，然后异步开始进行初始化操作
		templateAsync.initTemplate(requestHolder.getHost().getId(), requestHolder.getCurrentSite().getId(), userTemplateUnzipPath, insert);

		return JsonResult.messageSuccess("当前语点正在初始化！", updateSConfig);

	}

	protected OperateLog handletemplateLog(String templateName, String param)
			throws JsonParseException, JsonMappingException, JsonProcessingException, IOException {

		String declaringTypeName = "com.uduemc.biso.node.web.api.controller.ActionController";
		String modelName = OperateLoggerStaticModel.findModelName(declaringTypeName);
		String modelAction = OperateLoggerStaticModel.findModelAction(declaringTypeName, OperateLoggerStaticModelAction.UPDATE_THEMPLATE);
		String content = "手动导入模板（" + templateName + "）覆盖语点数据";
		short status = 2;

		Long hostId = requestHolder.getHost().getId();
		Long siteId = requestHolder.getCurrentSite().getId();
		Integer languageId = requestHolder.getCurrentSite().getLanguageId();
		LoginNode loginNode = requestHolder.getCurrentLoginNode();
		Long loginUserId = loginNode.getLoginUserId();
		String loginUserType = loginNode.getLoginUserType();
		String loginUserName = loginNode.getLoginUserName();
		String ipAddress = OperateLoggerController.ipAddress(requestHolder.getCurrentRequest());

		OperateLog operateLog = new OperateLog();
		operateLog.setHostId(hostId).setSiteId(siteId).setLanguageId(languageId).setUserId(loginUserId).setUserType(loginUserType).setUsername(loginUserName)
				.setModelName(modelName).setModelAction(modelAction).setContent(content).setParam(param).setReturnValue("").setOperateItem("").setStatus(status)
				.setIpaddress(ipAddress);

		OperateLog insert = operateLoggerServiceImpl.insert(operateLog);
		return insert;
	}

}
